package com.twinkle.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import com.twinkle.auth.constant.RedisKeyConstants;
import com.twinkle.auth.enums.LoginTypeEnum;
import com.twinkle.auth.enums.ResponseCodeEnum;
import com.twinkle.auth.model.vo.UpdatePasswordReqVO;
import com.twinkle.auth.model.vo.UserLoginReqVO;
import com.twinkle.auth.rpc.UserRpcService;
import com.twinkle.auth.service.AuthService;
import com.twinkle.framework.biz.context.holder.LoginUserContextHolder;
import com.twinkle.framework.common.exception.BusinessException;
import com.twinkle.framework.common.response.Response;
import com.twinkle.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Objects;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserRpcService userRpcService;

    @Override
    public Response<?> loginAndRegister(UserLoginReqVO userLoginVO) {
        String email = userLoginVO.getEmail();
        String password = userLoginVO.getPassword();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(userLoginVO.getType());
        // 登录类型错误
        if (Objects.isNull(loginTypeEnum)) {
            throw new BusinessException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }
        Long userId = null;

        //判断登录类型
        switch (loginTypeEnum) {
            case VERIFICATION_CODE:
                String verificationCode = userLoginVO.getCode();
                Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                String key = RedisKeyConstants.buildVerificationCodeKey(email);
                String sentCode = (String) redisTemplate.opsForValue().get(key);
                Preconditions.checkArgument(StringUtils.isNotBlank(sentCode), ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                Preconditions.checkArgument(sentCode != verificationCode, ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                userId = userRpcService.registerUser(email);
                if (Objects.isNull(userId)) {
                  throw new BusinessException(ResponseCodeEnum.LOGIN_ERROR);
                }
                break;
            case PASSWORD:
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRpcService.findUserByPhone(email);
                if (Objects.isNull(findUserByPhoneRspDTO)) {
                    throw new BusinessException(ResponseCodeEnum.USER_NOT_FOUND);
                }
                boolean matches = passwordEncoder.matches(password, findUserByPhoneRspDTO.getPassword());
                if (!matches) {
                    throw new BusinessException(ResponseCodeEnum.LOGIN_ERROR);
                }
                userId = findUserByPhoneRspDTO.getId();
                break;
            default:
                break;
        }

            StpUtil.login(userId);
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
            return Response.success(tokenInfo);
    }

    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();
        StpUtil.logout(userId);

        return Response.success();
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        // 新密码
        String newPassword = updatePasswordReqVO.getPassword();
        // 密码加密
        String encodePassword = passwordEncoder.encode(newPassword);

        // RPC: 调用用户服务：更新密码
        userRpcService.updatePassword(encodePassword);

        return Response.success();
    }


}
